package com.zrrd.common.util;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;
import java.util.List;

/**
 * @author WanJl
 * @version 1.0
 * @title MybatisPlusGeneratorUtil
 * @description mybatis-plus代码生成器工具类
 * @create 2024/4/1
 */
public class MybatisPlusGeneratorUtil {
    /**
     * 连接数据库的数据源
     */
    private String driverClassName = "com.mysql.cj.jdbc.Driver";
    /**
     * 连接数据库的url
     */
    private String url = "jdbc:mysql://localhost:3306/jt_manager_db?serverTimezone=UTC";
    /**
     * 连接数据库的username
     */
    private String username = "root";
    /**
     * 连接数据库的password
     */
    private String password = "123456";
    /**
     * 生成类名是要移除的表名前缀(如果表名存在前缀的话)
     */
    private String tablePrefix = "tb_";
    /**
     * 当前项目路径
     */
    private String projectPath = System.getProperty("user.dir");

    /**
     * 作者
     */
    private String author ="wanjl";
    /**
     * 父包名，与代码所在位置不冲突，二者叠加组成完整路径
     */
    private String basePackage = "com.zrrd";
    /**
     * 实体类包名
     */
    private String entityPackage = "entity";
    /**
     * 模块名
     *   为方便微服务拆分，如管理员模块持久层：admin.mapper,
     *   多级模块使用/进行分割，如：shop/goods、shop/ordered
     */
    private static String modulePackageName;

    private String moduleDirectoryName = modulePackageName.replace('.','/');

    /**
     * 当前项目java源码路径
     */
    private String javaDir = projectPath + "\\src\\main\\java";
    /**
     * 当前项目mapper层xml文件路径
     */
    private String xmlDir = projectPath + "\\src\\main\\resources\\mapper\\"+moduleDirectoryName+"\\";
    /**
     * 持久层包名
     */
    //private String mapperPackage = modulePackageName+"."+"mapper";
    private String mapperPackage = "mapper";
    /**
     * 服务层接口包名
     */
    //private String servicePackage = modulePackageName+"."+"service";
    private String servicePackage = "service";
    /**
     * 服务层实现类包名
     */
    //private String serviceImplPackage = modulePackageName+"."+"service.impl";
    private String serviceImplPackage = "service.impl";
    /**
     * 控制层包名
     */
    //private String controllerPackage = modulePackageName+"."+"controller";
    private String controllerPackage = "controller";
    /**
     * 要生成实体类的表名, 注意修改表名的同时记得修改moduleName的属性值
     */
    private static String[] tables;

    /**
     * 数据源配置
     *
     * @return
     */
    private DataSourceConfig setDataSourceConfig() {
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(url);
        dsc.setDriverName(driverClassName);
        dsc.setUsername(username);
        dsc.setPassword(password);
        return dsc;
    }

    /**
     * 全局配置
     *
     * @return
     */
    private GlobalConfig setGlobalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        //设置代码生成位置
        globalConfig.setOutputDir(javaDir);
        //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setOpen(false);
        //设置作者
        globalConfig.setAuthor(author);
        //设置是否覆盖原始生成的文件
        globalConfig.setFileOverride(true);
        //设置数据层接口名，%s为占位符，指代模块名称
        globalConfig.setMapperName("%sMapper");
        //设置数据层xml文件名
        globalConfig.setXmlName("%sMapper");
        //设置服务层接口名
        globalConfig.setServiceName("%sService");
        //设置服务层实现类名
        globalConfig.setServiceImplName("%sServiceImpl");
        //设置服务层实现类名
        globalConfig.setControllerName("%sController");
        //设置Id生成策略
        globalConfig.setIdType(IdType.AUTO);
        //在生成类的时候，自动配置Swagger2的相关注解
        globalConfig.setSwagger2(true);

        return globalConfig;
    }

    /**
     * 包名相关配置
     * @return
     */
    private PackageConfig setPackageConfig() {
        PackageConfig packageInfo = new PackageConfig();
        //设置生成的包名，与代码所在位置不冲突，二者叠加组成完整路径
        packageInfo.setParent(basePackage);
        //设置实体类包名
        packageInfo.setEntity(entityPackage);
        //设置数据层包名
        packageInfo.setMapper(mapperPackage);
        //设置服务层接口包名
        packageInfo.setService(servicePackage);
        //设置服务层实现类包名
        packageInfo.setServiceImpl(serviceImplPackage);
        //设置控制层包名
        packageInfo.setController(controllerPackage);
        return packageInfo;
    }

    /**
     * 策略相关配置
     * @return
     */
    private StrategyConfig setStrategyConfig() {
        StrategyConfig strategyConfig = new StrategyConfig();
        //设置当前参与生成的表名，参数为可变参数
        strategyConfig.setInclude(tables);
        //设置数据库表的前缀名称，模块名 = 数据库表名 - 前缀名  例如： Emp = tbl_emp - tbl_
        //strategyConfig.setTablePrefix(tablePrefix);
        //设置是否启用Rest风格
        strategyConfig.setRestControllerStyle(true);
        //设置乐观锁字段名
        //strategyConfig.setVersionFieldName("version");
        //设置逻辑删除字段名
        //strategyConfig.setLogicDeleteFieldName("deleted");
        //设置是否启用lombok
        strategyConfig.setEntityLombokModel(true);
        //类名生成策略：首字母大写驼峰式
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        //设置字段名生成策略：下划线转驼峰式
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        return strategyConfig;
    }

    /**
     * 自定义配置
     * @return
     */
    private InjectionConfig setInjectionConfig() {
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        // 如果模板引擎是 velocity
        String templatePath = "/templates/mapper.xml.vm";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                //String xmlName= StringUtils.capitalize(tableInfo.getName());
                // 自定义输出文件名 ， 如果 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return xmlDir + tableInfo.getEntityName()+ "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    /**
     * 配置模板
     * @return
     */
    private TemplateConfig setTemplateConfig() {
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        return templateConfig;
    }

    /**
     * 运行
     */
    private void run(){
        //1.创建代码生成器对象，执行代码生成操作
        AutoGenerator autoGenerator = new AutoGenerator();
        //2.数据源相关配置：读取数据库中的信息，根据数据库表结构生成代码
        autoGenerator.setDataSource(setDataSourceConfig());
        //3.设置全局配置
        autoGenerator.setGlobalConfig(setGlobalConfig());
        //4.设置包名相关配置
        autoGenerator.setPackageInfo(setPackageConfig());
        //5.设置策略相关配置
        autoGenerator.setStrategy(setStrategyConfig());
        //6.自定义配置-配置xml生成位置
        autoGenerator.setCfg(setInjectionConfig());
        //7.配置模板
        autoGenerator.setTemplate(setTemplateConfig());
        //8.执行生成代码操作
        autoGenerator.execute();
    }
    //每次生成之前，先修改静态代码块里面的属性值，会先加载，再加载对象
    static {
        modulePackageName="";
        tables=new String[]{"skus"};
        //{"role_rule"};
        //{"goods","goods_attrs","goods_banner","goods_skus","goods_skus_card","goods_skus_card_value","goods_type","goods_type_value"};
        //{"user", "user_addresses", "user_info", "user_level"};
    }
    public static void main(String[] args) {
        MybatisPlusGeneratorUtil util = new MybatisPlusGeneratorUtil();
        util.run();
    }
}
